// 通用的标签布局工具（基于像素）
// 使用方式（ES module）: import { adjustLabelsAfterRender } from './labelLayout.js'
function createTextMeasurer() {
  const canvas = document.createElement("canvas");
  const ctx = canvas.getContext("2d");
  return function measure(
    text,
    fontSize = 11,
    fontWeight = "bold",
    fontFamily = "sans-serif"
  ) {
    ctx.font = `${fontWeight} ${fontSize}px ${fontFamily}`;
    const metrics = ctx.measureText(text || "");
    return {
      width: Math.ceil(metrics.width) + 8,
      height: Math.ceil(fontSize) + 6,
    };
  };
}

function rectsOverlap(a, b) {
  return !(
    a.x + a.w < b.x ||
    a.x > b.x + b.w ||
    a.y + a.h < b.y ||
    a.y > b.y + b.h
  );
}

// chart: echarts 实例
// 返回: { updatedBarData, updatedLineData }
function adjustLabelsAfterRender(chart, categories, barData, lineData, opts) {
  opts = opts || {};
  const chartDom = chart.getDom();
  const chartRect = chartDom.getBoundingClientRect();
  const placedRects = [];
  const fontSizeDefault = opts.fontSizeDefault || 11;

  const updatedBarData = [];
  const updatedLineData = [];

  const measure = createTextMeasurer();
  const chartFontFamily =
    window.getComputedStyle(chartDom).fontFamily || "sans-serif";

  // 先获取像素位置
  const barPx = [];
  const linePx = [];
  for (let i = 0; i < categories.length; i++) {
    try {
      barPx[i] = chart.convertToPixel({ xAxisIndex: 0, yAxisIndex: 0 }, [
        categories[i],
        barData[i],
      ]);
      linePx[i] = chart.convertToPixel({ xAxisIndex: 0, yAxisIndex: 1 }, [
        categories[i],
        lineData[i],
      ]);
    } catch (e) {
      barPx[i] = [0, 0];
      linePx[i] = [0, 0];
    }
  }

  // 计算平均类目间距
  let avgSpacing = 0;
  if (barPx.length >= 2) {
    let sum = 0;
    let count = 0;
    for (let i = 1; i < barPx.length; i++) {
      const dx = Math.abs(barPx[i][0] - barPx[i - 1][0]);
      if (dx > 0) {
        sum += dx;
        count++;
      }
    }
    avgSpacing = count ? sum / count : 0;
  }

  // 估算平均标签宽度
  const sampleText = `${Math.max.apply(null, barData)}万元`;
  const sampleSize = measure(
    sampleText,
    fontSizeDefault,
    "bold",
    chartFontFamily
  );
  const avgLabelWidth = sampleSize.width;

  const isDense = avgSpacing > 0 && avgSpacing < avgLabelWidth * 0.9;

  // 候选偏移
  const candidates = opts.candidates || [-8, -24, -40, -56, 8, 24, 40, 56];
  const lineCandidates = opts.lineCandidates || [-8, -24, -40, 8, 24, 40];

  // 针对密集场景可增强参数
  const iterations = isDense
    ? opts.iterationsDense || 40
    : opts.iterations || 20;
  const maxShiftPerStep = opts.maxShiftPerStep || (isDense ? 8 : 6);

  // 为每个索引选择偏移（始终显示标签）
  for (let i = 0; i < categories.length; i++) {
    const barPosPx = barPx[i] || [0, 0];
    const linePosPx = linePx[i] || [0, 0];

    // 估算尺寸
    const barText = `${barData[i]}万元`;
    const lineText = `${lineData[i]}%`;
    let barFont = fontSizeDefault;
    let lineFont = fontSizeDefault;
    let barSize = measure(barText, barFont, "bold", chartFontFamily);
    let lineSize = measure(lineText, lineFont, "bold", chartFontFamily);

    // 如果密集，优先减小字体
    if (isDense) {
      barFont = Math.max(9, fontSizeDefault - 2);
      lineFont = Math.max(9, fontSizeDefault - 2);
      barSize = measure(barText, barFont, "bold", chartFontFamily);
      lineSize = measure(lineText, lineFont, "bold", chartFontFamily);
    }

    // 放柱状标签
    let chosenBarOffset = null;
    for (const dy of candidates) {
      const rect = {
        x: barPosPx[0] - barSize.width / 2,
        y: barPosPx[1] + dy - barSize.height,
        w: barSize.width,
        h: barSize.height,
      };

      // 不允许覆盖柱子顶部
      const barTopY = barPosPx[1];
      if (rect.y + rect.h > barTopY - 4) continue;

      let collide = false;
      for (const r of placedRects) {
        if (rectsOverlap(rect, r)) {
          collide = true;
          break;
        }
      }
      if (!collide) {
        chosenBarOffset = dy;
        placedRects.push(rect);
        break;
      }
    }

    if (chosenBarOffset === null) {
      // 缩小字体重试
      barFont = Math.max(8, barFont - 1);
      barSize = measure(barText, barFont, "bold", chartFontFamily);
      for (const dy of candidates) {
        const rect = {
          x: barPosPx[0] - barSize.width / 2,
          y: barPosPx[1] + dy - barSize.height,
          w: barSize.width,
          h: barSize.height,
        };
        if (rect.y + rect.h > barPosPx[1] - 2) continue;
        let collide = false;
        for (const r of placedRects) {
          if (rectsOverlap(rect, r)) {
            collide = true;
            break;
          }
        }
        if (!collide) {
          chosenBarOffset = dy;
          placedRects.push(rect);
          break;
        }
      }
    }

    if (chosenBarOffset === null) {
      chosenBarOffset = -8;
      placedRects.push({
        x: barPosPx[0] - barSize.width / 2,
        y: barPosPx[1] + chosenBarOffset - barSize.height,
        w: barSize.width,
        h: barSize.height,
      });
    }

    // 放折线标签
    let chosenLineOffset = null;
    for (const dy of lineCandidates) {
      const rect = {
        x: linePosPx[0] - lineSize.width / 2,
        y: linePosPx[1] + dy - lineSize.height,
        w: lineSize.width,
        h: lineSize.height,
      };
      let collide = false;
      for (const r of placedRects) {
        if (rectsOverlap(rect, r)) {
          collide = true;
          break;
        }
      }
      if (!collide) {
        chosenLineOffset = dy;
        placedRects.push(rect);
        break;
      }
    }

    if (chosenLineOffset === null) {
      lineFont = Math.max(8, lineFont - 1);
      lineSize = measure(lineText, lineFont, "bold", chartFontFamily);
      for (const dy of lineCandidates) {
        const rect = {
          x: linePosPx[0] - lineSize.width / 2,
          y: linePosPx[1] + dy - lineSize.height,
          w: lineSize.width,
          h: lineSize.height,
        };
        let collide = false;
        for (const r of placedRects) {
          if (rectsOverlap(rect, r)) {
            collide = true;
            break;
          }
        }
        if (!collide) {
          chosenLineOffset = dy;
          placedRects.push(rect);
          break;
        }
      }
    }

    if (chosenLineOffset === null) {
      chosenLineOffset = -8;
      placedRects.push({
        x: linePosPx[0] - lineSize.width / 2,
        y: linePosPx[1] + chosenLineOffset - lineSize.height,
        w: lineSize.width,
        h: lineSize.height,
      });
    }

    updatedBarData.push({
      value: barData[i],
      label: {
        show: true,
        position: [0, chosenBarOffset],
        textStyle: { fontSize: barFont, color: "#2c3e50" },
      },
    });
    updatedLineData.push({
      value: lineData[i],
      label: {
        show: true,
        position: [0, chosenLineOffset],
        textStyle: { fontSize: lineFont, color: "#e74c3c" },
      },
    });
  }

  // 对所有已放置标签做 X/Y 迭代推斥，减少重叠
  const rects = placedRects.map((r) => ({ x: r.x, y: r.y, w: r.w, h: r.h }));
  for (let it = 0; it < iterations; it++) {
    let moved = false;
    for (let a = 0; a < rects.length; a++) {
      for (let b = a + 1; b < rects.length; b++) {
        const A = rects[a];
        const B = rects[b];
        if (rectsOverlap(A, B)) {
          const Ax = A.x + A.w / 2;
          const Ay = A.y + A.h / 2;
          const Bx = B.x + B.w / 2;
          const By = B.y + B.h / 2;
          const dx = Ax - Bx;
          const dy = Ay - By;
          const overlapX = (A.w + B.w) / 2 - Math.abs(dx);
          const overlapY = (A.h + B.h) / 2 - Math.abs(dy);
          const dirX =
            dx === 0 ? (Math.random() > 0.5 ? 1 : -1) : dx / Math.abs(dx);
          const dirY =
            dy === 0 ? (Math.random() > 0.5 ? 1 : -1) : dy / Math.abs(dy);
          let shiftX = overlapX > 0 ? Math.ceil(overlapX / 2) * dirX : 0;
          let shiftY = overlapY > 0 ? Math.ceil(overlapY / 2) * dirY : 0;
          shiftX = Math.max(
            -maxShiftPerStep,
            Math.min(maxShiftPerStep, shiftX)
          );
          shiftY = Math.max(
            -maxShiftPerStep,
            Math.min(maxShiftPerStep, shiftY)
          );
          if (shiftX === 0 && shiftY === 0) {
            shiftY = dirY * 1;
          }
          A.x += shiftX;
          A.y += shiftY;
          B.x -= shiftX;
          B.y -= shiftY;
          A.x = Math.max(
            chartRect.left,
            Math.min(chartRect.left + chartRect.width - A.w, A.x)
          );
          B.x = Math.max(
            chartRect.left,
            Math.min(chartRect.left + chartRect.width - B.w, B.x)
          );
          A.y = Math.max(
            chartRect.top,
            Math.min(chartRect.top + chartRect.height - A.h, A.y)
          );
          B.y = Math.max(
            chartRect.top,
            Math.min(chartRect.top + chartRect.height - B.h, B.y)
          );
          moved = true;
        }
      }
    }
    if (!moved) break;
  }

  // 将最终位置回写为 label.position（基于像素位移）
  let prIndex = 0;
  for (let i = 0; i < categories.length; i++) {
    const barRect = rects[prIndex++];
    const newBarOffset = Math.round(
      barRect.y + barRect.h - (barPx[i] ? barPx[i][1] : 0)
    );
    const barItem = updatedBarData[i];
    if (barItem && barItem.label) barItem.label.position = [0, newBarOffset];
    const lineRect = rects[prIndex++];
    const newLineOffset = Math.round(
      lineRect.y + lineRect.h - (linePx[i] ? linePx[i][1] : 0)
    );
    const lineItem = updatedLineData[i];
    if (lineItem && lineItem.label)
      lineItem.label.position = [0, newLineOffset];
  }

  return { updatedBarData, updatedLineData };
}

export { adjustLabelsAfterRender };
